package org.kca.yarmour.view;

import java.util.*;
import org.kca.graphics.Animation;
import org.kca.graphics.Displayable;

/**
 * An class representing an animated and moving sprite. Movement and animation are
 * handled together. A sprite can have multiple static and animated images, and
 * are able to toggle between them. For best effects, the animations used should 
 * be looping, or longer than the duration of movement.
 * @author ctheng
 *
 */
public class AnimatedSprite implements Displayable
{
    private double x, y;
    private double vx, vy;
    private long time, timeLimit;
    private boolean moving;
    private int activeIndex;
    private List<Animation> animationList;
    
    public AnimatedSprite()
    {
        animationList = new ArrayList<Animation>();
        activeIndex = -1;
    }

    /**
     * Gets the x coordinate rounded to nearest integer
     * @return the x coordinate
     */
    public int getX()
    {
        return (int)Math.round(x);
    }
    
    /**
     * Sets the x coordinate
     * @param x the x coordinate to set
     */
    public void setX(double x)
    {
        this.x = x;
    }
    
    /**
     * Gets the y coordinate rounded to nearest integer
     * @return the y coordinate
     */
    public int getY()
    {
        return (int)Math.round(y);
    }
    
    /**
     * Sets the y coordinate
     * @param y the y coordinate to set
     */
    public void setY(double y)
    {
        this.y = y;
    }
    
    /**
     * Checks if this sprite is moving
     * @return true if the sprite is moving
     */
    public boolean isMoving()
    {
        return moving;
    }
    
    /**
     * Adds an animation to the animation list. 
     * @param anim the animation to add
     */
    public void addAnimation(Animation anim)
    {
        animationList.add(anim);
        activeIndex = 0;
    }
    
    /**
     * Changes the current animation. Enters the new animation in a reset
     * state, but does not start it.
     * @param index the index of the animation to change to
     */
    public void setActiveAnimation(int index)
    {
        if (index >= 0 && index < animationList.size() && activeIndex != index)
        {
            activeIndex = index;
            animationList.get(activeIndex).reset();
        }
    }
    
    /**
     * Gets the index of the active animation
     * @return the index of the active animation
     */
    public int getActiveAnimation()
    {
        return activeIndex;
    }
    
    /**
     * Gets a stored animation by index
     * @param index the index of the animation
     * @return the animation corresponding to that index or null if index is invalid
     */
    public Animation getAnimation(int index)
    {
        if (index >= 0 && index < animationList.size())
        {
            return animationList.get(index);
        }
        return null;
    }
    
    /**
     * Starts the active animation
     */
    public void startActiveAnimation()
    {
        if (activeIndex != -1)
        {
            animationList.get(activeIndex).start();
        }
    }
    
    /**
     * Resets the active animation
     */
    public void resetActiveAnimation()
    {
        if (activeIndex != -1)
        {
            animationList.get(activeIndex).reset();
        }
    }
    
    /**
     * Starts movement of the animated sprite. If the sprite was already moving, this
     * method will override the existing movement and restart the animation.
     * @param vx the x velocity in pixels/ms
     * @param vy the y velocity in pixels/ms
     * @param duration the time in ms to move for
     */
    public void startMovement(double vx, double vy, long duration)
    {
        this.vx = vx;
        this.vy = vy;
        time = 0;
        timeLimit = duration;
        moving = true;
        startActiveAnimation();
    }

    @Override
    public void drawComponent(int x, int y)
    {
        if (activeIndex != -1)
        {
            animationList.get(activeIndex).drawComponent(x + getX(), y + getY());
        }
    }
    
    @Override
    public void update(long elapsedTime)
    {
        if (moving)
        {
            if (time + elapsedTime > timeLimit)
            {
                elapsedTime = timeLimit - time;
                time = 0;
                moving = false;
                resetActiveAnimation();
            }
            else
            {
                time += elapsedTime;
            }
            x += vx * elapsedTime;
            y += vy * elapsedTime;
        }
        if (activeIndex != -1)
        {
            animationList.get(activeIndex).update(elapsedTime);
        }
    }
    
}
